﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.IO;
using System.Linq;
using BankCreditPortfolio.DAL.Entities;
using BankCreditPortfolio.DAL.Services;

namespace BankCreditPortfolio.Models.ClientCabinetModels
{
    public class DrawOrderModel :IBaseModel<OrderInfo>
    {
        public DrawOrderModel()
        {
            SelectedTariff = (new TariffService()).GetAll().Count() > 0 ? 
                (new TariffService()).GetAll().First().Title : string.Empty;
            Tariffs = (new TariffService()).GetAll().Where(x => x.Used).ToList();
            GainCurrencies = (new CurrencyService()).CreateQuery().ToList();
            GuarantorCurrencies = (new CurrencyService()).CreateQuery().ToList();
        }

        public string SelectedTariff { get; set; }
        public IEnumerable<Tariff> Tariffs { get; set; }
        public string DocumentPath { get; set; }
        public bool GuarantorsRequired { get; set; }
        public string ClientName { get; set; }
        public int GainCurrencyId { get; set; }
        public int GuarantorCurrencyId { get; set; }
            
        [Display(Name = "Credit Tariff")]
        public string TariffTitle { get; set; }

        [Range(1, 2000000000)]
        [Display(Name = "Amount")]
        [RegularExpression(@"^ *[1-9]+[0-9]* *$", ErrorMessage = "Amount should be positive integer number.")]
        public int? Amount { get; set; }

        [Range(1, 2000000000)]
        [RegularExpression(@"^ *[1-9]+[0-9]* *$", ErrorMessage = "Income should be positive integer number from 1 to 2000000000.")]
        [Display(Name = "Income")]
        public decimal? Gains { get; set; }

        [Display(Name = "Currency Of Income")]
        public List<Currency> GainCurrencies { get; set; }

        [Display(Name = "Documents"), StringLength(4000)]
        public string Documents { get; set; }

        [StringLength(40)]
        [Display(Name = "First name")]
        [RegularExpression(@"^ *([A-Z][a-z]*[\s-']?)*([A-Z][a-z]*)* *$", ErrorMessage = "First name is not valid")]
        public string FirstName { get; set; }

        [StringLength(40)]
        [Display(Name = "Last name")]
        [RegularExpression(@"^ *([A-Z][a-z]*[\s-']?)*([A-Z][a-z]*)* *$", ErrorMessage = "First name is not valid")]
        public string LastName { get; set; }

        [StringLength(40)]
        [Display(Name = "Middle name")]
        [RegularExpression(@"^ *([A-Z][a-z]*[\s-']?)*([A-Z][a-z]*)* *$", ErrorMessage = "First name is not valid")]
        public string MiddleName { get; set; }

        [StringLength(14, ErrorMessage = "The {0} must be {2} characters long.", MinimumLength = 14)]
        [Display(Name = "Personal Number")]
        [RegularExpression(@"^ *([0-9]{7}[a-zA-Z][0-9]{3}[a-zA-Z]{2}[0-9])? *$", ErrorMessage = "The {0} is in incorrect format.")]
        public string PersonalId { get; set; }

        [DataType(DataType.Date)]
        [DisplayFormat(NullDisplayText = "", DataFormatString = "{0:MM/dd/yyyy}")]
        [RegularExpression(@"^(([1-9]|0[1-9]|1[012])/([1-9]|0[1-9]|[12][0-9]|3[01])/[0-9]{4})?$", ErrorMessage = "The {0} is incorrectly formatted. Right format: MM/DD/YYYY.")]
        [Display(Name = "Date of passport delivery")]
        public string PassportDate { get; set; }

        [StringLength(255/*, MinimumLength = 4*/)]
        [Display(Name = "Passport issuing authority")]
        public string PassportIssuingAuthority { get; set; }

        [Display(Name = "Address")]
        [StringLength(255/*, MinimumLength = 4*/)]
        public string Address { get; set; }

        [DataType(DataType.PhoneNumber)]
        [Display(Name = "Phone")]
        [RegularExpression(@"^ *(\+[0-9]{5} [0-9]{7})? *$", ErrorMessage = "The {0} is not in international format (+XXXXX XXXXXXX).")]
        public string Phone { get; set; }

        [StringLength(255/*, MinimumLength = 4*/)]
        [Display(Name = "Workplace")]
        public string Workplace { get; set; }

        [Range(1, 2000000000)]
        [Display(Name = "Income")]
        [RegularExpression(@"^ *([1-9]+[0-9]*)? *$", ErrorMessage = "Income should be positive integer number from 1 to 2000000000.")]
        public decimal? GuarantorGains { get; set; }

        [Display(Name = "Currency Of Income")]
        public List<Currency> GuarantorCurrencies { get; set; }

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            var tariff = (new TariffService()).GetByTitle(TariffTitle);
            if (string.IsNullOrEmpty(TariffTitle))
                yield return new ValidationResult(RequiredMessage("Credit Tariff"), new[] { "TariffTitle" });
            if (!Amount.HasValue)
                yield return new ValidationResult(RequiredMessage("Amount"), new[] { "Amount" });
            if ((Amount < tariff.Min)||(Amount > tariff.Max))
                yield return new ValidationResult("Amount value should be between Min and Max sum from the tariff.", new[] { "Amount" });
            if (!Gains.HasValue)
                yield return new ValidationResult(RequiredMessage("Income"), new[] { "Gains" });

            if (tariff.NumberOfGuarantors > 0)
            {

                if (string.IsNullOrEmpty(FirstName))
                    yield return new ValidationResult(RequiredMessage("First name"), new[] { "FirstName" });
                if (string.IsNullOrEmpty(LastName))
                    yield return new ValidationResult(RequiredMessage("Last name"), new[] { "LastName" });
                if (string.IsNullOrEmpty(MiddleName))
                    yield return new ValidationResult(RequiredMessage("Middle name"), new[] { "MiddleName" });

                if (string.IsNullOrEmpty(PersonalId))
                    yield return new ValidationResult(RequiredMessage("Personal number"), new[] { "PersonalId" });

                if (string.IsNullOrEmpty(PassportDate))
                    yield return new ValidationResult(RequiredMessage("Date of passport delivery"), new[] { "PassportDate" });
                else
                {
                    DateTime date;
                    if (!DateTime.TryParse(PassportDate, CultureInfo.CreateSpecificCulture("en-US"), DateTimeStyles.None, out date))
                    {
                        yield return new ValidationResult("The passport delivery date is incorrect. Format: MM/DD/YYYY.",
                            new[] { "PassportDate" });
                    }
                    else
                    {
                        var minDate = DateTime.Today.AddYears(-10);
                        var maxDate = DateTime.Today;

                        if (date < minDate || date > maxDate)
                        {
                            yield return new ValidationResult(String.Format("The passport delivery date must be between {0} and {1}.",
                                minDate.ToShortDateString(), maxDate.ToShortDateString()),
                                new[] { "PassportDate" });
                        }
                    }
                }

                if (string.IsNullOrEmpty(PassportIssuingAuthority))
                    yield return new ValidationResult(RequiredMessage("Passport issuing authority"), new[] { "PassportIssuingAuthority" });
                else if (PassportIssuingAuthority.Length < 4)
                    yield return new ValidationResult("The field Passport issuing authority must be a string with a minimum length of 4 and a maximum length of 255.", new[] { "PassportIssuingAuthority" });
                
                if (string.IsNullOrEmpty(Address))
                    yield return new ValidationResult(RequiredMessage("Address"), new[] { "Address" });
                else if (Address.Length < 4)
                    yield return new ValidationResult("The field Address must be a string with a minimum length of 4 and a maximum length of 255.", new[] { "Address" });

                if (string.IsNullOrEmpty(Phone))
                    yield return new ValidationResult(RequiredMessage("Phone"), new[] { "Phone" });

                if (string.IsNullOrEmpty(Workplace))
                    yield return new ValidationResult(RequiredMessage("Workplace"), new[] { "Workplace" });
                else if (Workplace.Length < 4)
                    yield return new ValidationResult("The field Workplace must be a string with a minimum length of 4 and a maximum length of 255.", new[] { "Workplace" });
                   

                if (!GuarantorGains.HasValue)
                    yield return new ValidationResult(RequiredMessage("Income"), new[] { "GuarantorGains" });
            }
        }

        private string RequiredMessage(string fieldName)
        {
            return string.Format("The {0} field is required.", fieldName);
        }

        public IBaseModel<OrderInfo> MapFrom(OrderInfo @from)
        {
            throw new NotImplementedException();
        }

        public OrderInfo MapTo(OrderInfo to)
        {
            var tariff = (new TariffService()).GetByTitle(TariffTitle);

            to.Gains = Gains.Value;
            to.OrderStatus = (new OrderStatusService()).GetByTitle("Received for review");
            to.Tariff = tariff;
            to.Currency = tariff.Currency;
            to.Amount = Amount.Value;
            to.Client = (new ClientService()).GetByEmail(ClientName);
            to.GainsCurrency = (new CurrencyService()).Find(GainCurrencyId);
            try
            {
                (new OrderInfoService()).Save(ref to);
            }
            catch (Exception ex)
            {
                return null;
            }

            if (GuarantorsRequired)
            {
                var profile = new Profile
                {
                    Adress = Address,
                    Phone = Phone,
                    FirstName = FirstName,
                    LastName = LastName,
                    MiddleName = MiddleName,
                    PassportIssuingAuthority = PassportIssuingAuthority,
                    PassportDate = DateTime.Parse(PassportDate),
                    PersonalId = PersonalId,
                    Work = Workplace
                };
                var guarantor = new Guarantor
                {
                    Gains = Gains.Value,
                    GainsCurrency = (new CurrencyService()).Find(GuarantorCurrencyId),
                    Profile = profile,
                    OrderInfo = to,
                };
                try
                {
                    (new ProfileService()).Save(ref profile);
                    (new GuarantorService()).Save(ref guarantor);
                }
                catch (Exception ex)
                {
                    return null;
                }
            }
            
            return to;
        }
    }
}